﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using AnthStat.Domain.Collections;

namespace AnthStat.WPF.Applications
{
    public sealed class CsvExporterViewModel : ViewModelBase
    {
        private readonly ProjectViewModel _projectViewModel;
        private string _fileName = String.Empty;
        private bool _isDisplaying = false;
        private bool _isDisplayingResults = false;
        private bool _isExporting = false;
        private double _exportProgress = 0.0;
        private string _recordsExported = String.Empty;

        public CsvExporterViewModel(ProjectViewModel projectViewModel)
        {
            _projectViewModel = projectViewModel;
            FileName = String.Empty;
        }

        public double ExportProgress
        {
            get
            {
                return _exportProgress;
            }
            private set
            {
                _exportProgress = value;
                RaisePropertyChanged("ExportProgress");
            }
        }

        public string RecordsExported
        {
            get
            {
                return _recordsExported;
            }
            private set
            {
                _recordsExported = value;
                RaisePropertyChanged("RecordsExported");
            }
        }

        public string FileName
        {
            get
            {
                return _fileName;
            }
            set
            {
                _fileName = value;
                RaisePropertyChanged("FileName");
            }
        }

        public bool IsDisplaying
        {
            get
            {
                return _isDisplaying;
            }
            set
            {
                _isDisplaying = value;
                RaisePropertyChanged("IsDisplaying");
            }
        }

        public bool IsDisplayingResults
        {
            get
            {
                return _isDisplayingResults;
            }
            set
            {
                _isDisplayingResults = value;
                RaisePropertyChanged("IsDisplayingResults");
            }
        }

        public bool IsExporting
        {
            get
            {
                return _isExporting;
            }
            private set
            {
                _isExporting = value;
                RaisePropertyChanged("IsExporting");
            }
        }

        public ICommand CloseCsvExporterCommand { get { return new RelayCommand(CloseCsvExporterCommandExecute, CanExecuteCloseCsvExporterCommand); } }
        private void CloseCsvExporterCommandExecute()
        {
            IsDisplaying = false;
            IsDisplayingResults = false;
        }

        private bool CanExecuteCloseCsvExporterCommand()
        {
            if (IsExporting) return false;
            return true;
        }

        public ICommand ExportCommand { get { return new RelayCommand(ExportCommandExecute, CanExecuteExportCommand); } }
        private void ExportCommandExecute()
        {
            Task.Factory.StartNew(
            () =>
                {
                    RecordsExported = String.Empty;
                    ExportTo(FileName);
                },
                System.Threading.CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).ContinueWith(
                delegate
                {
                    IsExporting = false;
                    ExportProgress = 0.0;

                    CommandManager.InvalidateRequerySuggested();

                }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private bool CanExecuteExportCommand()
        {
            if (IsExporting || String.IsNullOrEmpty(FileName)) return false;
            return true;
        }

        /// <summary>
        /// Exports the AnthStat data to a CSV file
        /// </summary>
        /// <param name="fileName">The file name where the resulting CSV data shall reside</param>
        /// <returns>bool; whether or not the operation was successful</returns>
        private bool ExportTo(string fileName)
        {
            Contract.Requires(!String.IsNullOrEmpty(fileName));

            IsExporting = true;
            IsDisplayingResults = true;
            ExportProgress = 0.0;

            bool success = false;

            // Ideally this logic would go at a lower level but because of PCL concerns with writing to text files, this is being placed in App layer instead

            int rows = 0;

            try
            {
                using (StreamWriter writer = new StreamWriter(fileName))
                {
                    writer.WriteLine("sep=;");

                    StringBuilder sb = new StringBuilder();

                    sb.Append("GlobalRecordId;");
                    sb.Append("NumericId;");
                    sb.Append("UserCreated;");
                    sb.Append("UserUpdated;");
                    sb.Append("DateCreated;");
                    sb.Append("DateUpdated;");

                    if (_projectViewModel.DataCaptureMode == Domain.DataCaptureMode.NutritionalSurvey)
                    {
                        sb.Append("Team;");
                        sb.Append("Cluster;");
                        sb.Append("Household;");
                    }

                    sb.Append("LastName;");
                    sb.Append("FirstName;");
                    sb.Append("Sex;");
                    //sb.Append("Race;");
                    //sb.Append("Ethnicity;");
                    sb.Append("DateBirth;");
                    sb.Append("IsDateBirthEstimated;");
                    sb.Append("StreetAddress;");
                    sb.Append("City;");
                    sb.Append("Adm1;");
                    sb.Append("Adm2;");
                    sb.Append("Adm3;");
                    sb.Append("PostalCode;");
                    sb.Append("Country;");
                    //sb.Append("HomePhoneNumber;");
                    //sb.Append("WorkPhoneNumber;");
                    //sb.Append("CellPhoneNumber;");
                    //sb.Append("Email;");                
                    //sb.Append("Latitude;");
                    //sb.Append("Longitude");

                    sb.Append("SurveyDate;");

                    sb.Append("AgeDays").Append(";");
                    sb.Append("AgeMonths").Append(";");
                    sb.Append("AgeYears").Append(";");

                    sb.Append("BodyMassIndex").Append(";");
                    sb.Append("HasOedema").Append(";");
                    sb.Append("HeadCircumference").Append(";");
                    sb.Append("Height").Append(";");
                    sb.Append("Weight").Append(";");
                    sb.Append("SubscapularSkinfold").Append(";");
                    sb.Append("TricepsSkinfold").Append(";");
                    sb.Append("MidUpperArmCircumference").Append(";");
                    sb.Append("IsRecumbent").Append(";");
                    sb.Append("Notes").Append(";");
                    sb.Append("WHOBMIP").Append(";");
                    sb.Append("WHOBMIZ").Append(";");
                    sb.Append("WHOHAP").Append(";");
                    sb.Append("WHOHAZ").Append(";");
                    sb.Append("WHOHCP").Append(";");
                    sb.Append("WHOHCZ").Append(";");
                    sb.Append("WHOMUACP").Append(";");
                    sb.Append("WHOMUACZ").Append(";");
                    sb.Append("WHOSSFP").Append(";");
                    sb.Append("WHOSSFZ").Append(";");
                    sb.Append("WHOTSFP").Append(";");
                    sb.Append("WHOTSFZ").Append(";");
                    sb.Append("WHOWAP").Append(";");
                    sb.Append("WHOWAZ").Append(";");
                    sb.Append("WHOWHP").Append(";");
                    sb.Append("WHOWHZ").Append(";");

                    writer.WriteLine(sb.ToString());

                    double increment = 1.0 / (double)(_projectViewModel.ChildrenView.SourceCollection.Cast<PersonViewModel>().Count());

                    foreach (PersonViewModel p in _projectViewModel.ChildrenView.SourceCollection)
                    {
                        ExportProgress += increment;

                        foreach (MeasurementViewModel m in p.MeasurementsView)
                        {
                            sb = new StringBuilder();

                            sb.Append(p.GlobalRecordId).Append(";");
                            sb.Append(p.NumericId).Append(";");
                            sb.Append(p.UserCreated).Append(";");
                            sb.Append(p.UserUpdated).Append(";");
                            sb.Append(p.DateCreated).Append(";");
                            sb.Append(p.DateUpdated).Append(";");

                            if (_projectViewModel.DataCaptureMode == Domain.DataCaptureMode.NutritionalSurvey)
                            {
                                sb.Append(p.Team).Append(";");
                                sb.Append(p.Cluster).Append(";");
                                sb.Append(p.Household).Append(";");
                            }
                            sb.Append(p.LastName).Append(";");
                            sb.Append(p.FirstName).Append(";");
                            sb.Append(p.Sex).Append(";");
                            //sb.Append(p.Race).Append(";");
                            //sb.Append(p.Ethnicity).Append(";");
                            sb.Append(p.DateBirth).Append(";");
                            sb.Append(p.IsDateBirthEstimated).Append(";");
                            sb.Append(p.StreetAddress).Append(";");
                            sb.Append(p.City).Append(";");
                            sb.Append(p.Adm1).Append(";");
                            sb.Append(p.Adm2).Append(";");
                            sb.Append(p.Adm3).Append(";");
                            sb.Append(p.PostalCode).Append(";");
                            sb.Append(p.Country).Append(";");
                            //sb.Append(p.HomePhoneNumber).Append(";");
                            //sb.Append(p.WorkPhoneNumber).Append(";");
                            //sb.Append(p.CellPhoneNumber).Append(";");
                            //sb.Append(p.Email).Append(";");
                            //sb.Append(p.Latitude).Append(";");
                            //sb.Append(p.Longitude).Append(";");

                            sb.Append(m.DateMeasurement).Append(";");

                            sb.Append(m.AgeDays).Append(";");
                            sb.Append(m.AgeMonths).Append(";");
                            sb.Append(m.AgeYears).Append(";");

                            sb.Append(m.BodyMassIndex).Append(";");
                            sb.Append(m.HasOedema).Append(";");
                            sb.Append(m.HeadCircumference).Append(";");
                            sb.Append(m.Height).Append(";");
                            sb.Append(m.Weight).Append(";");
                            sb.Append(m.SubscapularSkinfold).Append(";");
                            sb.Append(m.TricepsSkinfold).Append(";");
                            sb.Append(m.MidUpperArmCircumference).Append(";");
                            sb.Append(m.IsRecumbent).Append(";");
                            sb.Append(m.Notes).Append(";");
                            sb.Append(m.WHOBMIP).Append(";");
                            sb.Append(m.WHOBMIZ).Append(";");
                            sb.Append(m.WHOHAP).Append(";");
                            sb.Append(m.WHOHAZ).Append(";");
                            sb.Append(m.WHOHCP).Append(";");
                            sb.Append(m.WHOHCZ).Append(";");
                            sb.Append(m.WHOMUACP).Append(";");
                            sb.Append(m.WHOMUACZ).Append(";");
                            sb.Append(m.WHOSSFP).Append(";");
                            sb.Append(m.WHOSSFZ).Append(";");
                            sb.Append(m.WHOTSFP).Append(";");
                            sb.Append(m.WHOTSFZ).Append(";");
                            sb.Append(m.WHOWAP).Append(";");
                            sb.Append(m.WHOWAZ).Append(";");
                            sb.Append(m.WHOWHP).Append(";");
                            sb.Append(m.WHOWHZ).Append(";");

                            writer.WriteLine(sb.ToString());

                            rows++;

                            //System.Threading.Thread.Sleep(500); // so fast for small data that can't see progress bar
                        }
                    }

                    writer.WriteLine();
                }

                RecordsExported = rows.ToString() + " records written.";
            }
            catch (Exception)
            {
                success = false;
            }
            finally
            {
                IsExporting = false;
            }

            return success;
        }
    }
}
